package com.cy.cy2025.util

import android.Manifest
import android.content.Context
import android.location.Address
import android.location.Geocoder
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.Build
import androidx.annotation.RequiresPermission
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.cy.cy2025.MyApplication
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.util.Locale


/**
 * android原生定位工具类
 */
object LocationManagerUtil {

    // 定位管理器
    private val locationManager by lazy {
        MyApplication.app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
    }

    // 定位监听器
    private val _location = MutableLiveData<Location>()
    val location: LiveData<Location?> = _location

    // 系统定位监听器
    private val locationUpdateListener = object : LocationListener {
        override fun onLocationChanged(newLocation: Location) {
            if (newLocation.provider == LocationManager.NETWORK_PROVIDER) {
                // 网络定位精度较低，只在当前定位结果为空，或者离上次定位结果超过一个定位周期时使用
                if (_location.value == null ||
                    (newLocation.time - (location.value?.time ?: 0)) >= LOCATION_UPDATE_INTERVAL
                ) {
                    _location.value = newLocation
                }
            } else {//gps定位精度更高，直接使用gps定位结果
                _location.value = newLocation
            }
        }

        override fun onProviderDisabled(provider: String) {
            ToastUtil.showShort("定位服务已关闭，请开启后重试")
        }
    }

    // 定位周期，单位毫秒
    const val LOCATION_UPDATE_INTERVAL = 10000L

    /**
     * 开始定位更新，该方法会先获取最后已知的位置，然后请求位置更新。
     */

    fun startLocationUpdates() {
        PermissionUtil.requestPermissions(object : PermissionsCallback {
            @RequiresPermission(allOf = [Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION])
            override fun onSuccess() {
                if (isLocationEnabled()) {
                    val lastKnownLocation = getLastKnownLocation()
                    lastKnownLocation?.let {
                        _location.value = it
                    }
                    requestLocationUpdates()
                } else {
                    ToastUtil.showShort("定位服务未开启，请前往设置中开启")
                }
            }

            override fun onFailure(
                failures: List<String>,
                forbiddings: List<String>
            ) {
                ToastUtil.showShort("未获得定位权限")
            }
        }, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION)
    }

    /**
     * 停止定位更新
     */
    fun stopLocationUpdates() {
        locationManager.removeUpdates(locationUpdateListener)
    }

    /**
     * 检查定位服务是否开启
     */
    private fun isLocationEnabled(): Boolean {
        return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) == true
                || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) == true
    }

    /**
     * 获取最后已知的位置
     */
    @RequiresPermission(allOf = [Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION])
    private fun getLastKnownLocation(): Location? {
        // 优先获取GPS定位
        val gpsLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
        if (gpsLocation != null) {
            return gpsLocation
        }
        // GPS定位不可用，尝试获取网络定位
        return locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
    }

    /**
     * 请求定位更新
     */

    @RequiresPermission(allOf = [Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION])
    private fun requestLocationUpdates() {
        // 请求GPS定位，每隔10秒更新一次位置信息，最小距离为10米
        locationManager.requestLocationUpdates(
            LocationManager.GPS_PROVIDER,
            LOCATION_UPDATE_INTERVAL,
            10f,
            locationUpdateListener
        )
        // 请求网络定位，每隔10秒更新一次位置信息，最小距离为10米
        locationManager.requestLocationUpdates(
            LocationManager.NETWORK_PROVIDER,
            LOCATION_UPDATE_INTERVAL,
            10f,
            locationUpdateListener
        )
    }


    /**
     * 根据地址获取经纬度信息（地理编码）
     */
    suspend fun getLocationFromAddress(address: String): List<Address> =
        withContext(Dispatchers.IO) {
            val deferred = CompletableDeferred<List<Address>>()
            val geocoder = Geocoder(MyApplication.app, Locale.CHINA)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                geocoder.getFromLocationName(address, 5) {
                    deferred.complete(it)
                }
                return@withContext deferred.await()
            } else {
                @Suppress("DEPRECATION")
                return@withContext geocoder.getFromLocationName(address, 5) ?: emptyList()
            }
        }


    /**
     * 根据经纬度获取地址信息（反地理编码）
     */
    suspend fun getAddressFromLocation(latitude: Double, longitude: Double): List<String> =
        withContext(Dispatchers.IO) {
            val geocoder = Geocoder(MyApplication.app, Locale.CHINA)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                val deferred = CompletableDeferred<List<String>>()
                geocoder.getFromLocation(latitude, longitude, 5) {
                    deferred.complete(
                        it.map {
                            //行政等级
                            val maxAddressLineIndex = it.maxAddressLineIndex
                            it.getAddressLine(maxAddressLineIndex)
                        }.toList()
                    )
                }
                return@withContext deferred.await()
            } else {
                @Suppress("DEPRECATION")
                return@withContext geocoder.getFromLocation(latitude, longitude, 5)?.map {
                    //行政等级
                    val maxAddressLineIndex = it.maxAddressLineIndex
                    it.getAddressLine(maxAddressLineIndex)
                }?.toList() ?: emptyList()
            }

        }

}